﻿using System;
using System.Collections.Generic;
using PES.Common.DAL;
using log4net;
using Campeonato.Model.Sort;

namespace PES.Common.BLL
{
    using Model;

    public class CampeonatoBLL
    {
        private static ILog s_logger;
        public static ILog Logger
        {
            get { return s_logger ?? (s_logger = LogManager.GetLogger("CampeonatoBLL")); }
        }

        private static CampeonatoDAL s_campDAL;
        private static CampeonatoDAL CampDAL
        {
            get { return s_campDAL ?? (s_campDAL = new CampeonatoDAL()); }
        }

        private static PartidaDAL s_partidaDAL;
        private static PartidaDAL PartidaDAL
        {
            get { return s_partidaDAL ?? (s_partidaDAL = new PartidaDAL()); }
        }
        
        public static void CadastraCampeonato(Campeonato _campeonato)
        {
            try
            {
                if (_campeonato == null)
                {
                    throw new ApplicationException("Campeonato não pode ser nulo.");
                }

                if (string.IsNullOrEmpty(_campeonato.Nome))
                {
                    throw new ApplicationException("Nome não pode ser nulo ou vazio.");
                }

                if (CampDAL.ExisteCampeonato(_campeonato.Nome))
                {
                    throw new ApplicationException(string.Format(
                        "Já existe um campeonato com esse nome, escolha outro ({0}).", _campeonato.Nome));
                }

                CampDAL.CadastraCampeonato(_campeonato);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao cadastrar campeonato.", ex);
                throw;
            }
        }

        public static void FinalizarCampeonato(Campeonato _campeonato)
        {
            try
            {
                if (_campeonato == null || _campeonato.ID <= 0)
                {
                    throw new ApplicationException("Parâmetro inválido");
                }

                CampDAL.FinalizarCampeonato(_campeonato.ID);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao finalizar campeonato.", ex);
                throw;
            }
        }

        public static IList<Campeonato> BuscarTodosCampeonatos()
        {
            try
            {
                return CampDAL.BuscarTodosCampeonatos(true, false);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao buscar todos os campeonatos.", ex);
                throw;
            }
        }
        
        public static IList<Campeonato> BuscarCampeonatosNaoFinalizados()
        {
            try
            {
                return CampDAL.BuscarTodosCampeonatos(false, false);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao buscar todos os campeonatos não finalizados.", ex);
                throw;
            }
        }

        public static IList<Jogador> BuscarRankingCampeonato(Campeonato _campeonato)
        {
            try
            {
                return CampDAL.BuscarRankingCampeonato(_campeonato.ID);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao buscar o ranking do Campeonato.", ex);
                throw;
            }
        }

        public static Campeonato BuscarCampeonato(int _campeonatoID)
        {
            try
            {
                return CampDAL.BuscarCampeonato(_campeonatoID);
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao buscar o Campeonato.", ex);
                throw;
            }
        }

        public static IList<Jogador> BuscarRankingCampeonatoPorTurno(Campeonato _campeonato, int _turno)
        {
            try
            {
                if (_campeonato == null || _campeonato.ID <= 0)
                {
                    throw new ApplicationException("Campeonato inválido.");
                }

                if (_turno < 1 || _turno > 2)
                {
                    throw new ApplicationException("Turno inválido.");
                }

                Campeonato camp = CampDAL.BuscarCampeonato(_campeonato.ID);

                int rodadaInicial = (camp.QuantidadeRodadas / 2) * (_turno - 1) + 1;
                int rodadaFinal = (camp.QuantidadeRodadas / 2) * (_turno);

                var partidas = new List<Partida>();

                for (int i = rodadaInicial; i <= rodadaFinal; i++)
                {
                    partidas.AddRange(PartidaDAL.BuscarPartidasPorRodada(_campeonato.ID, i));
                }

                var jogadores = new List<Jogador>();

                foreach (Partida p in partidas)
                {
                    Jogador jogador1 = p.Jogador1;
                    Jogador j1 = jogadores.Find(_j => _j.ID == jogador1.ID);
                    if (j1 == null)
                    {
                        j1 = jogador1;
                        j1.Pontos = new Pontuacao();
                        jogadores.Add(j1);
                    }

                    Jogador jogador2 = p.Jogador2;
                    Jogador j2 = jogadores.Find(_j => _j.ID == jogador2.ID);
                    if (j2 == null)
                    {
                        j2 = jogador2;
                        j2.Pontos = new Pontuacao();
                        jogadores.Add(j2);
                    }

                    Pontuacao pontuacaoJogador1 = j1.Pontos;
                    Pontuacao pontuacaoJogador2 = j2.Pontos;

                    if (p.GolsJogador1.HasValue)
                    {
                        if (p.GolsJogador1 == p.GolsJogador2)
                        {
                            pontuacaoJogador1.NumEmpates++;
                            pontuacaoJogador2.NumEmpates++;

                            pontuacaoJogador1.TotalPontos++;
                            pontuacaoJogador2.TotalPontos++;
                        }
                        else if (p.GolsJogador1 > p.GolsJogador2)
                        {
                            pontuacaoJogador1.NumVitorias++;
                            pontuacaoJogador2.NumDerrotas++;

                            pontuacaoJogador1.TotalPontos += 3;                            
                        }
                        else
                        {
                            pontuacaoJogador2.NumVitorias++;
                            pontuacaoJogador1.NumDerrotas++;

                            pontuacaoJogador2.TotalPontos += 3;
                        }

                        pontuacaoJogador1.GolsPro += p.GolsJogador1.Value;
                        pontuacaoJogador1.GolsContra += p.GolsJogador2.Value;
                        pontuacaoJogador2.GolsPro += p.GolsJogador2.Value;
                        pontuacaoJogador2.GolsContra += p.GolsJogador1.Value;
                    }
                }

                jogadores.Sort(ComparadorRanking.ComparaJogadoresRanking);

                return jogadores;
            }
            catch (Exception ex)
            {
                Logger.Error("Ocorreu um erro ao buscar o ranking do Campeonato.", ex);
                throw;
            }
        }        
    }
}
